#ifndef SHM_H
#define SHM_H
#include <sys/ipc.h>
#include <sys/stat.h>
#include <sys/shm.h>
#include "testbase.h"

class Shm : public TestBase {
    enum : int {
        READ = 0x01,
        WRITE = 0x02,
        DEL = 0x04
    };

    int parse() {
        int cmd = 0;
        if(argc_ > 1) {
            const std::string str = argv_[1];
            for(const auto& ch : str) {
                if(ch == 'R' || ch == 'r') cmd |= READ;
                else if(ch == 'W' || ch == 'w') cmd |= WRITE;
                else if(ch == 'D' || ch == 'd') cmd |= DEL;
            }
        }
        return cmd;
    }

public:
    Shm(int argc=0, char** argv=nullptr)
        : TestBase(argc, argv), bufsize(4096)
        , cmd(parse()), valid(false)
        , shmId(-1), shmBuf(nullptr)
    {
        auto key = ftok(path, 2);
        shmId = shmget(key, 0, IPC_CREAT); //  __size=0为:获取共享内存, >0创建
        if(shmId == -1) {
            shmId = shmget(key, bufsize, IPC_CREAT|0666);// 内存块大小4KB
            valid = shmId!=-1;
            cout << "shm id:" << shmId << endl;
            if(!valid) {
                puts("shm get fail");
                return;
            }
        }
        shmBuf = (char*)shmat(shmId, nullptr, 0);
        cout << "buf : " << sizeof(shmBuf) << "  " << &shmBuf << endl;
    }

    void write(const std::string& str) {
        memcpy(shmBuf, str.data(), str.size());
    }

    void read() {
        cout << "read : " << shmBuf << endl;
    }

    void test() override {
        if(!valid) {
            puts("test fail");
            return;
        }

        if(cmd&WRITE) {
            memset(shmBuf, 0, bufsize);
            write("test shm");
        }

        if(cmd&READ) {
            read();
        }

        if(cmd&DEL) {
            int ret = shmctl(shmId, IPC_RMID, nullptr);
            if(ret) puts("del fail");
            else puts("del succeed");
        }
    }

private:
    const int bufsize;
    const char* path = "/temp";
    const int cmd;
    bool valid;
    int shmId;
    char* shmBuf;
};

#endif // SHM_H
